package com.voice.call.utils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * HTTP传输器
 * 
 * <pre>
 * 负责发送HTTP请求，支持GET, POST方式
 * </pre>
 * 
 * @author qugf
 * 
 */
public class HttpTransport {
	private static final Logger LOG = LoggerFactory
			.getLogger(HttpTransport.class);

	private HttpTransport() {

	}

	/**
	 * 构建请求配置对象，这里主要设置请求的超时时间
	 * 
	 * @param connectTimeout 客户端连接到url的连接等待时间（毫秒），该值为0时表示无限超时
	 * @param socketTimeout 读取数据超时时间（毫秒），既两个连续的数据包之间的最长不活动时间，该值为0时表示无限超时
	 * @param connectRequestTimeout 从连接管理器获取连接的超时时间，该值为0时表示无限超时
	 * @return 请求配置对象
	 */
	RequestConfig buildRequestConfig(Integer connectTimeout,
			Integer socketTimeout, Integer connectRequestTimeout) {
		Builder rcBuilder = RequestConfig.custom();
		if (connectTimeout != null && connectTimeout > 0) {
			rcBuilder.setConnectTimeout(connectTimeout);
		}

		if (socketTimeout != null && socketTimeout > 0) {
			rcBuilder.setSocketTimeout(socketTimeout);
		}

		if (connectRequestTimeout != null && connectRequestTimeout > 0) {
			rcBuilder.setConnectionRequestTimeout(connectRequestTimeout);
		}

		return rcBuilder.build();
	}

	/**
	 * 向服务器发起HTTP POST请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param headers 消息请求头
	 * @param requestBody 消息请求体
	 * @param charset 字符编码，默认使用UTF-8编码
	 * @param readTimeout 读取数据超时时间
	 * @param responseHandler 响应处理器
	 * @return 响应结果数据
	 */
	public String doPost(String url, Map<String, String> headers,
			Map<String, String> requestBody, Charset charset,
			Integer readTimeout, ResponseHandler<String> responseHandler) {
		CloseableHttpClient httpClient = HttpClientConnectionManager
				.getHttpClientInstance();

		RequestConfig requestConfig = buildRequestConfig(null, readTimeout,
				null);
		HttpPost post = new HttpPost(url);
		post.setConfig(requestConfig);

		// 设置消息头
		if (headers != null && !headers.isEmpty()) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				post.setHeader(entry.getKey(), entry.getValue());
			}
		}

		// 构建消息体
		List<NameValuePair> entity = new ArrayList<NameValuePair>();
		if (requestBody != null && !requestBody.isEmpty()) {
			for (Map.Entry<String, String> entry : requestBody.entrySet()) {
				entity.add(new BasicNameValuePair(entry.getKey(), entry
						.getValue()));
			}
		}

		try {
			post.setEntity(new UrlEncodedFormEntity(entity, charset));
			String responseBody = httpClient.execute(post,
					responseHandler != null ? responseHandler
							: new StringResponseHandler(charset));
			return responseBody;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}

		return null;
	}

	/**
	 * 向服务器发起HTTP POST请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param headers 消息请求头
	 * @param requestBody 消息请求体
	 * @param charset 字符编码，默认使用UTF-8编码
	 * @param readTimeout 读取数据超时时间
	 * @param responseHandler 响应处理器
	 * @return 响应结果数据
	 */
	public String doPost(String url, Map<String, String> headers,
			String requestBody, Charset charset, Integer readTimeout,
			ResponseHandler<String> responseHandler) {
		CloseableHttpClient httpClient = HttpClientConnectionManager
				.getHttpClientInstance();

		RequestConfig requestConfig = buildRequestConfig(null, readTimeout,
				null);
		HttpPost post = new HttpPost(url);
		post.setConfig(requestConfig);

		// 设置消息头
		if (headers != null && !headers.isEmpty()) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				post.setHeader(entry.getKey(), entry.getValue());
			}
		}

		try {
			String entity = requestBody == null ? "" : requestBody;
			Charset _charset = charset == null ? Consts.UTF_8 : charset;
			post.setEntity(new StringEntity(entity, _charset));

			String responseBody = httpClient.execute(post,
					responseHandler != null ? responseHandler
							: new StringResponseHandler(charset));
			return responseBody;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}

		return null;
	}
	
	
	/**
	 * 向服务器发起HTTP PUT请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param headers 消息请求头
	 * @param requestBody 消息请求体
	 * @param charset 字符编码，默认使用UTF-8编码
	 * @param readTimeout 读取数据超时时间
	 * @param responseHandler 响应处理器
	 * @return 响应结果数据
	 */
	public String doPut(String url, Map<String, String> headers,
			String requestBody, Charset charset, Integer readTimeout,
			ResponseHandler<String> responseHandler) {
		CloseableHttpClient httpClient = HttpClientConnectionManager
				.getHttpClientInstance();

		RequestConfig requestConfig = buildRequestConfig(null, readTimeout,
				null);
		HttpPut put = new HttpPut(url);
		put.setConfig(requestConfig);

		// 设置消息头
		if (headers != null && !headers.isEmpty()) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				put.setHeader(entry.getKey(), entry.getValue());
			}
		}

		try {
			String entity = requestBody == null ? "" : requestBody;
			Charset _charset = charset == null ? Consts.UTF_8 : charset;
			
			if(entity!=null && entity.length() > 0){
				put.setEntity(new StringEntity(entity, _charset));
			}
			

			String responseBody = httpClient.execute(put,
					responseHandler != null ? responseHandler
							: new StringResponseHandler(charset));
			return responseBody;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}

		return null;
	}

	/**
	 * 向服务器发起HTTP POST请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param charset 字符编码，默认使用UTF-8编码
	 * @param requestBody 消息体
	 * @return 响应结果数据
	 */
	public String doPost(String url, String requestBody, Charset charset) {
		return this.doPost(url, null, requestBody, charset, null,
				new StringResponseHandler());
	}
	
	/**
	 * 向服务器发起HTTP PUT请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param charset 字符编码，默认使用UTF-8编码
	 * @param requestBody 消息体
	 * @return 响应结果数据
	 */
	public String doPut(String url, String requestBody, Charset charset) {
		return this.doPut(url, null, requestBody, charset, null,
				new StringResponseHandler());
	}
	
	public String doPut(String url,Map<String,String> heads, String requestBody) {
		return this.doPut(url, heads, requestBody, Consts.UTF_8, null,
				new StringResponseHandler());
	}

	/**
	 * 向服务器发起HTTP POST请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param charset 字符编码，默认使用UTF-8编码
	 * @param requestBody 消息体
	 * @param readTimeout 读取数据超时时间
	 * @return 响应结果数据
	 */
	public String doPost(String url, String requestBody, Charset charset,
			Integer readTimeout) {
		return this.doPost(url, null, requestBody, charset, readTimeout,
				new StringResponseHandler());
	}

	/**
	 * 向服务器发起HTTP POST请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param requestBody 消息体
	 * @param readTimeout 读取数据超时时间
	 * @return 响应结果数据
	 */
	public String doPost(String url, String requestBody, Integer readTimeout) {
		return this.doPost(url, null, requestBody, Consts.UTF_8, readTimeout,
				new StringResponseHandler());
	}
	
	/**
	 * 向服务器发起HTTP POST请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param headers 消息请求头
	 * @param requestBody 消息体
	 * @return 响应结果数据
	 */
	public String doPost(String url, Map<String, String> headers, String requestBody) {
		return this.doPost(url, headers, requestBody, Consts.UTF_8, null,
				new StringResponseHandler());
	}

	/**
	 * 向服务器发起HTTP POST请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param requestBody 消息体
	 * @return 响应结果数据
	 */
	public String doPost(String url, String requestBody) {
		return this.doPost(url, null, requestBody, Consts.UTF_8, null,
				new StringResponseHandler());
	}
	
	public String doJSONPost(String url, String requestBody) {
		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Content-Type", "application/json");
		headers.put("Accept", "application/json");
		return this.doPost(url, headers, requestBody, Consts.UTF_8, 60000,
				new StringResponseHandler());
	}
	
	
	/**
	 * 向服务器发起HTTP PUT请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param requestBody 消息体
	 * @return 响应结果数据
	 */
	public String doPut(String url, String requestBody) {
		return this.doPut(url, null, requestBody, Consts.UTF_8, null,
				new StringResponseHandler());
	}
	/**
	 * 向服务器发起HTTP GET请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param charset 字符编码，默认使用UTF-8编码
	 * @param readTimeout 读取数据超时时间
	 * @param responseHandler 响应结果处理器
	 * @return 响应结果数据
	 */
	public String doGet(String url, Charset charset, Integer readTimeout, ResponseHandler<String> responseHandler) {
		CloseableHttpClient httpClient = HttpClientConnectionManager.getHttpClientInstance();
		RequestConfig requestConfig = buildRequestConfig(null, readTimeout, null);
		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(requestConfig);
		try {
			return httpClient.execute(httpGet,
					responseHandler != null ? responseHandler
							: new StringResponseHandler(charset));
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}

		return null;
	}

	public String doGet(String url, Charset charset, int readTimeout) {
		return this.doGet(url, charset, 0, new StringResponseHandler());
	}
	
	/**
	 * 
	 * @param url 服务器Url
	 * @param readTimeout 读取数据超时时间
	 * @return 响应结果数据
	 */
	public String doGet(String url, int readTimeout) {
		return this.doGet(url, Consts.UTF_8, 0, new StringResponseHandler());
	}

	/**
	 * 向服务器发起HTTP GET请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @return 响应结果数据
	 */
	public String doGet(String url) {
		return this.doGet(url, Consts.UTF_8, 0, new StringResponseHandler());
	}

	/**
	 * 向服务器发起HTTP GET请求，返回响应结果数据
	 * 
	 * @param url 服务器Url
	 * @param params 查询字符串参数
	 * @param readTimeout 读取数据超时时间
	 * @return 响应结果数据
	 */
	public String doGet(String url, Map<String, String> params, int readTimeout, ResponseHandler<String> responseHandler) {
		String _url = null;
		try {
			URIBuilder uriBuilder = new URIBuilder(url);
			// 设置消息头
			if (params != null && !params.isEmpty()) {
				for (Map.Entry<String, String> entry : params.entrySet()) {
					uriBuilder.setParameter(entry.getKey(), entry.getValue());
				}
			}
			_url = uriBuilder.build().toString();
			System.out.println(_url);
		} catch (URISyntaxException e) {
			LOG.error("invalid uri![{}]", url);
			return null;
		}
		return this.doGet(_url, Consts.UTF_8, 0, responseHandler);
	}
	
	
	public String doPATCH(String url,Map<String,String> heads,String bodyData, Charset charset, Integer readTimeout, ResponseHandler<String> responseHandler) {
		CloseableHttpClient httpClient = HttpClientConnectionManager.getHttpClientInstance();
		RequestConfig requestConfig = buildRequestConfig(null, readTimeout, null);
		
		HttpPatch httpGet = new HttpPatch(url);
		httpGet.setConfig(requestConfig);
		
		//设置请求头
				if(heads!=null && heads.size()>0){
					
					for (Map.Entry<String, String> entry : heads.entrySet()) { 
						httpGet.setHeader(entry.getKey(), entry.getValue());  
						//url_con.setRequestProperty(entry.getKey(), entry.getValue()); 
					}
				}
				if(bodyData!=null){
					httpGet.setEntity(new StringEntity(bodyData, Consts.UTF_8));
				}
		try {
			return httpClient.execute(httpGet,
					responseHandler != null ? responseHandler
							: new StringResponseHandler(charset));
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}

		return null;
	}
	
	public String doPATCH(String url,Map<String,String> headers,String bodyData) {
		return this.doPATCH(url,headers,bodyData, Consts.UTF_8, 0, new StringResponseHandler());
	}

	public static HttpTransport getInstance() {
		return getInstance(true);
	}

	public static HttpTransport getInstance(boolean keepAlive) {
		return HttpTransportHolder.transport;
	}

	public static class HttpTransportHolder {
		final static HttpTransport transport = new HttpTransport();
	}

	/**
	 * 字符串类型Response处理器
	 * 
	 * @author qugf
	 * 
	 */
	public static class StringResponseHandler implements
			ResponseHandler<String> {

		private Charset charset = Consts.UTF_8;

		public StringResponseHandler() {

		}

		public StringResponseHandler(Charset charset) {
			if (charset != null) {
				this.charset = charset;
			}
		}

		@Override
		public String handleResponse(HttpResponse response)
				throws ClientProtocolException, IOException {
			StatusLine statusLine = response.getStatusLine();
			HttpEntity entity = response.getEntity();
			if (statusLine.getStatusCode() >= 300) {
				EntityUtils.consume(entity);
				throw new HttpResponseException(statusLine.getStatusCode(),
						statusLine.getReasonPhrase());
			}

			if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
				return entity != null ? EntityUtils.toString(entity, charset)
						: null;
			}

			return null;
		}
	}
	
	
	
}
/***
public class HttpPatch extends HttpPut {  
    public HttpPatch(String url) {  
        super(url);  
    }  
    @Override  
    public String getMethod() {  
        return "PATCH";  
    }  
}  
**/
